﻿#region Includes
using System;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics.OpenGL;
using GingerGL;
using GingerGL.Math;
#endregion

namespace GingerGL.Graphics
{
    //------------------------------------------------------------//
    /// <summary>
    /// Scene Camera
    /// </summary>
    public abstract class Camera : Frustum, IRenderable
    {
        //--------------------------------------------------------//
        #region Properties
        /// <summary>
        /// Gets TRUE to draw object to screen
        /// </summary>
        public bool Visible { get; set; }
        /// <summary>
        /// Gets/Sets Camera Offsets
        /// </summary>
        public Vector3 Offset { get; set; }
        //--------------------------------------------------------//
        #region Orientation
        /// <summary>
        /// Gets Camera Position
        /// </summary>
        public Vector3 Position { get; protected set; }
        /// <summary>
        /// Gets Camera Target Vector
        /// </summary>
        public Vector3 View { get; protected set; }
        /// <summary>
        /// Gets Camera Up Vector
        /// </summary>
        public Vector3 Up { get; protected set; }
        /// <summary>
        /// Calculates Forward Direction
        /// </summary>
        public Vector3 Forward { get { Vector3 d = this.View - this.Position; d.Normalize(); return d; } }
        /// <summary>
        /// Calculates Right Vector
        /// </summary>
        public Vector3 Right { get { Vector3 r = Vector3.Cross(this.Forward, this.Up); r.Normalize(); return r; } }
        #endregion
        //--------------------------------------------------------//
        #region Speeds
        /// <summary>
        /// Gets/Sets speed of up/down movement
        /// </summary>
        public float ElevateSpeed { get; set; }
        /// <summary>
        /// Gets/Sets speed of left/right movement
        /// </summary>
        public float DisplaceSpeed { get; set; }
        /// <summary>
        /// Gets/Sets speed of forward/backward movement
        /// </summary>
        public float MoveSpeed { get; set; }
        /// <summary>
        /// Gets/Sets speed of wheel up/down movement
        /// </summary>
        public float WheelSpeed { get; set; }
        /// <summary>
        /// Gets/Sets speed of rotation
        /// </summary>
        public float RotateSpeed { get; set; }
        #endregion
        //--------------------------------------------------------//
        #endregion
        //--------------------------------------------------------//
        #region Constructors
        /// <summary>
        /// Camera Structure
        /// </summary>
        protected Camera()
        {
            this.Offset = new Vector3(0, 0, 0);
            this.Position = new Vector3(0, 0, 0);
            this.View = new Vector3(0, 0, 1);
            this.Up = new Vector3(0, 1, 0);
            this.DisplaceSpeed = 15;
            this.ElevateSpeed = 15;
            this.MoveSpeed = 15;
            this.RotateSpeed = 1;
            this.Visible = true;
        }
        /// <summary>
        /// Camera Structure
        /// </summary>
        public Camera(Vector3 position, Vector3 view, Vector3 up) : this()
        {
            this.Position = position;
            this.View = view;
            this.Up = up;
        }
        #endregion
        //--------------------------------------------------------//
        #region Methods
        /// <summary>
        /// Draws Camera to Screen
        /// </summary>
        public void Draw() { if (this.Visible) Update(); } 
        /// <summary>
        /// Moves Camera Forward and Backward
        /// </summary>
        public abstract void Move(MoveDirection direction);
        /// <summary>
        /// Moves Camera Left and Right
        /// </summary>
        public abstract void Displace(DisplaceDirection direction);
        /// <summary>
        /// Moves Camera Up and Down
        /// </summary>
        public abstract void Elevate(ElevationDirection direction);
        /// <summary>
        /// Moves Camera Position
        /// </summary>
        public abstract void Set(Vector3 pos);
        /// <summary>
        /// Update Camera to Screen
        /// </summary>
        protected abstract void Update();
        /// <summary>
        /// Camera's Reset Function
        /// </summary>
        public abstract void Reset();
        /// <summary>
        /// Mouse Move Listener
        /// </summary>
        public abstract void MouseMove(MouseMoveEventArgs e);
        /// <summary>
        /// Centers Mouse on Primary Screen
        /// </summary>
        static public void CenterMouse()
        {
            if (Engine.Instance.GameWindow.Focused)             //does the window have focus?
                Mouse.SetPosition                               //center the mouse then
                (
                    System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width * 0.5f,
                    System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height * 0.5f
                );
        }
        /// <summary>
        /// Gets Hash Code
        /// </summary>
        public override int GetHashCode()
        {
            return this.GetHashCode()
                    ^ this.DisplaceSpeed.GetHashCode()
                    ^ this.ElevateSpeed.GetHashCode()
                    ^ this.Enabled.GetHashCode()
                    ^ this.MoveSpeed.GetHashCode()
                    ^ this.Planes.GetHashCode()
                    ^ this.Position.GetHashCode()
                    ^ this.RotateSpeed.GetHashCode()
                    ^ this.Up.GetHashCode()
                    ^ this.View.GetHashCode()
                    ^ this.WheelSpeed.GetHashCode();
        }
        /// <summary>
        /// Equals
        /// </summary>
        public override bool Equals(object obj) { return base.Equals(obj); }
        /// <summary>
        /// Camera ToString
        /// </summary>
        public override string ToString()
        {
            return String.Format(
                "Camera - Position: {0} View: {1} Up: {2}",
                this.Position,
                this.View,
                this.Up);

        }
        /// <summary>
        /// Disposes of object
        /// </summary>
        public void Dispose() { /*nothing*/ }
        #endregion
        //--------------------------------------------------------//
}
    //------------------------------------------------------------//
}
